﻿/*
 * datetime.cpp
 *
 *  Created on: 2017年7月6日
 *      Author: Dylan.Gao
 */

#include <dm/export.hpp>

#define DM_API_MISC DM_API_EXPORT

#include <dm/datetime.hpp>
#include <dm/timestamp.hpp>
#include <dm/runtimestamp.hpp>
#include <ctime>
#include <cstdio>
#include <cstdlib>

#ifndef WIN32
#include <sys/time.h>
#endif

namespace dm{

CDateTime::CDateTime():
		m_year(0),m_month(0),m_day(0),
		m_hour(0),m_minute(0),m_sec(0),
		m_msec(0){
}

CDateTime::CDateTime( const CDateTime& dt ):
		m_year(dt.m_year),m_month(dt.m_month),m_day(dt.m_day),
		m_hour(dt.m_hour),m_minute(dt.m_minute),m_sec(dt.m_sec),
		m_msec(dt.m_msec){
}

CDateTime::CDateTime( const CTimeStamp& ts ){
	*this = ts;
}

CDateTime::CDateTime( const CRunTimeStamp& rts ){
	*this = rts.toTimeStamp();
}

CDateTime::CDateTime( const volatile CDateTime& dt ):
		m_year(dt.m_year),m_month(dt.m_month),m_day(dt.m_day),
		m_hour(dt.m_hour),m_minute(dt.m_minute),m_sec(dt.m_sec),
		m_msec(dt.m_msec){
}

CDateTime::CDateTime( const volatile CTimeStamp& ts ){
	*this = ts;
}

CDateTime::CDateTime( const volatile CRunTimeStamp& rts ):CDateTime(CRunTimeStamp(rts).toTimeStamp()){
}

CDateTime& CDateTime::operator =( const CDateTime& dt ){
	m_year = dt.m_year;
	m_month = dt.m_month;
	m_day = dt.m_day;
	m_hour = dt.m_hour;
	m_minute = dt.m_minute;
	m_sec = dt.m_sec;
	m_msec = dt.m_msec;

	return *this;
}

CDateTime& CDateTime::operator =( const CTimeStamp& ts ){
	std::time_t tt = ts.seconds();
#ifdef WIN32
	std::tm tm;
	localtime_s(&tm, &tt);
	m_year = tm.tm_year + 1900;
	m_month = tm.tm_mon + 1;
	m_day = tm.tm_mday;
	m_hour = tm.tm_hour;
	m_minute = tm.tm_min;
	m_sec = tm.tm_sec;
#else
	std::tm* tmt = std::localtime(&tt);
	m_year = tmt->tm_year + 1900;
	m_month = tmt->tm_mon + 1;
	m_day = tmt->tm_mday;
	m_hour = tmt->tm_hour;
	m_minute = tmt->tm_min;
	m_sec = tmt->tm_sec;
#endif

	m_msec = ts.mseconds();

	return *this;
}

CDateTime& CDateTime::operator =( const CRunTimeStamp& rts ){
	return *this = rts.toTimeStamp();
}

CDateTime& CDateTime::operator =( const volatile CDateTime& dt ){
	m_year = dt.m_year;
	m_month = dt.m_month;
	m_day = dt.m_day;
	m_hour = dt.m_hour;
	m_minute = dt.m_minute;
	m_sec = dt.m_sec;
	m_msec = dt.m_msec;

	return *this;
}

CDateTime& CDateTime::operator =( const volatile CTimeStamp& ts ){
	std::time_t tt = ts.seconds();
#ifdef WIN32
	std::tm tm;
	localtime_s(&tm, &tt);
	m_year = tm.tm_year + 1900;
	m_month = tm.tm_mon + 1;
	m_day = tm.tm_mday;
	m_hour = tm.tm_hour;
	m_minute = tm.tm_min;
	m_sec = tm.tm_sec;
#else
	std::tm* tmt = std::localtime(&tt);
	m_year = tmt->tm_year + 1900;
	m_month = tmt->tm_mon + 1;
	m_day = tmt->tm_mday;
	m_hour = tmt->tm_hour;
	m_minute = tmt->tm_min;
	m_sec = tmt->tm_sec;
#endif
	m_msec = ts.mseconds();

	return *this;
}

CDateTime& CDateTime::operator =( const volatile CRunTimeStamp& rts ){
	return *this = CRunTimeStamp(rts).toTimeStamp();
}

bool CDateTime::operator ==( const CDateTime& dt )const{
	return m_year==dt.m_year && m_month==dt.m_month && m_day==dt.m_day && m_hour==dt.m_hour \
			&& m_minute==dt.m_minute && m_sec==dt.m_sec && m_msec==dt.m_msec;
}

bool CDateTime::isValid()const{
	return (m_year>=1900) && (m_month>=1 && m_month<=12) && (m_day>0 && m_day<=31 ) \
			&& ( m_hour<24 ) && m_minute<60 && m_sec<60 && m_msec<1000;
}

CDateTime::EWeekDay CDateTime::getWeekDay()const{
	std::tm tmt;
	tmt.tm_year = m_year - 1900;
	tmt.tm_mon = m_month - 1;
	tmt.tm_mday = m_day;
	tmt.tm_hour = m_hour;
	tmt.tm_min = m_minute;
	tmt.tm_sec = m_sec;

	std::mktime(&tmt);

	return EWeekDay(tmt.tm_wday);
}

void CDateTime::setYear( dm::uint16 year ){
	if( year>=1900 )
		m_year = year;
}

void CDateTime::setMonth( dm::uint8 month ){
	if( month>0 && month<=12 )
		m_month = month;
}

void CDateTime::setDay( dm::uint8 day ){
	if( day>0 && day<32 )
		m_day = day;
}

void CDateTime::setHour( dm::uint8 hour ){
	if( hour<24 )
		m_hour = hour;
}

void CDateTime::setMinute( dm::uint8 minute ){
	if( minute<60 )
		m_minute = minute;
}

void CDateTime::setSec( dm::uint8 sec ){
	if( sec<60 )
		m_sec = sec;
}

void CDateTime::setMsec( dm::uint16 msec ){
	if( msec<1000 )
		m_msec = msec;
}

void CDateTime::toTimeStamp( CTimeStamp& ts )const{
	std::tm tmt;
	tmt.tm_year = m_year - 1900;
	tmt.tm_mon = m_month - 1;
	tmt.tm_mday = m_day;
	tmt.tm_hour = m_hour;
	tmt.tm_min = m_minute;
	tmt.tm_sec = m_sec;

	ts.setSeconds(std::mktime(&tmt));
	ts.setMseconds( m_msec );
}

CTimeStamp CDateTime::toTimeStamp()const{
	CTimeStamp ts;
	toTimeStamp(ts);
	return ts;
}

std::ostream& operator<<( std::ostream& ostr,const CDateTime& dt ){
	return ostr <<(int)dt.year()<<'-'<<(int)dt.month()<<'-'<<(int)dt.day()<<' '<<(int)dt.hour()<<':'<<(int)dt.minute()<<':'<<dt.sec()+dt.msec()*0.001;
}

std::string CDateTime::toString()const{
	char s[32];
#ifdef WIN32
	sprintf_s<32>(s,"%04d-%02d-%02d %02d:%02d:%02d.%03d", m_year, m_month, m_day, m_hour, m_minute, m_sec, m_msec);
#else
	std::sprintf(s,"%04d-%02d-%02d %02d:%02d:%02d.%03d",m_year,m_month,m_day,m_hour,m_minute,m_sec,m_msec);
#endif
	return s;
}

bool CDateTime::fromString( const char* str ){
	int year,month,day,hour,minute;
	float sec;
#ifdef WIN32
	if (6 != sscanf_s(str, "%d-%d-%d %d:%d:%f", &year, &month, &day, &hour, &minute, &sec))
		return false;
#else
	if( 6!=sscanf(str,"%d-%d-%d %d:%d:%f",&year,&month,&day,&hour,&minute,&sec) )
		return false;
#endif		

	setYear(year);
	setMonth(month);
	setDay(day);
	setHour(hour);
	setMinute(minute);
	setSec((dm::uint8)sec);
	setMsec( dm::uint16((sec-int(sec))*1000) );

	return true;
}

/**
 * 获取今天的起始时刻
 * @param now 现在时刻
 * @return
 */
CDateTime CDateTime::today()const{
	CDateTime dt(*this);
	dt.setHour(0);
	dt.setMinute(0);
	dt.setSec(0);
	dt.setMsec(0);
	return dt;
}

/**
 * 获取本月开始时刻
 * @return
 */
CDateTime CDateTime::thisMonth()const{
	CDateTime dt(*this);
	dt.setDay(1);
	dt.setHour(0);
	dt.setMinute(0);
	dt.setSec(0);
	dt.setMsec(0);
	return dt;
}

CDateTime CDateTime::thisYear()const{
	CDateTime dt(*this);
	dt.setMonth(1);
	dt.setDay(1);
	dt.setHour(0);
	dt.setMinute(0);
	dt.setSec(0);
	dt.setMsec(0);
	return dt;
}

/**
 * 获取昨天的起始时刻
 * @return
 */
CDateTime CDateTime::yesterday()const{
	return yesterday(this->toTimeStamp());
}

/**
 * 获取上个月起始时刻
 * @return
 */
CDateTime CDateTime::lastMonth()const{
	CDateTime dt(*this);
	if( dt.month()==1 ){
		dt.setYear(dt.year()-1);
		dt.setMonth(12);
	}else{
		dt.setMonth(dt.month()-1);
	}

	return dt;
}

CDateTime CDateTime::lastYear()const{
	CDateTime dt(*this);
	dt.setYear(dt.year()-1);
	return dt;
}

CDateTime CDateTime::tomorrow()const{
	return tomorrow(this->toTimeStamp());
}

CDateTime CDateTime::nextMonth()const{
	CDateTime dt(*this);
	if( dt.month()==12 ){
		dt.setYear(dt.year()+1);
		dt.setMonth(1);
	}else{
		dt.setMonth(dt.month()+1);
	}

	return dt;
}

CDateTime CDateTime::nextYear()const{
	CDateTime dt(*this);
	dt.setYear(dt.year()+1);
	return dt;
}

/**
 * 获取今天起始时刻
 * @see today()
 * @param now
 * @return
 */
CDateTime CDateTime::today( const CTimeStamp& now ){
	return CDateTime(now).today();
}

/**
 * 获取本月起始时刻
 * @see thisMonth()
 * @param now
 * @return
 */
CDateTime CDateTime::thisMonth( const CTimeStamp& now ){
	return CDateTime(now).thisMonth();
}

/**
 * 获取今年起始时刻
 * @see thisYear()
 * @param now
 * @return
 */
CDateTime CDateTime::thisYear( const CTimeStamp& now ){
	return CDateTime(now).thisYear();
}

/**
 * 获取昨天起始时刻
 * @param now
 * @return
 */
CDateTime CDateTime::yesterday( const CTimeStamp& now ){
	return today(CTimeStamp(now.seconds()-24*3600,0));
}

CDateTime CDateTime::lastMonth( const CTimeStamp& now ){
	return CDateTime(now).lastMonth();
}

CDateTime CDateTime::lastYear( const CTimeStamp& now ){
	return CDateTime(now).lastYear();
}

CDateTime CDateTime::tomorrow( const CTimeStamp& now ){
	return today(CTimeStamp(now.seconds()+24*3600,0));
}

CDateTime CDateTime::nextMonth( const CTimeStamp& now ){
	return CDateTime(now).nextMonth();
}

CDateTime CDateTime::nextYear( const CTimeStamp& now ){
	return CDateTime(now).nextYear();
}

/**
 * 获取当天起始时刻
 * @param now
 * @return
 */
CDateTime CDateTime::today( const CDateTime& now ){
	CDateTime dt(now);
	dt.setHour(0);
	dt.setMinute(0);
	dt.setSec(0);
	dt.setMsec(0);

	return dt;
}

/**
 * 获取当月起始时刻
 * @param now
 * @return
 */
CDateTime CDateTime::thisMonth( const CDateTime& now ){
	CDateTime dt(now);
	dt.setDay(1);
	dt.setHour(0);
	dt.setMinute(0);
	dt.setSec(0);
	dt.setMsec(0);

	return dt;
}

/**
 * 获取当年起始时刻
 * @param now
 * @return
 */
CDateTime CDateTime::thisYear( const CDateTime& now ){
	CDateTime dt(now);
	dt.setMonth(1);
	dt.setDay(1);
	dt.setHour(0);
	dt.setMinute(0);
	dt.setSec(0);
	dt.setMsec(0);

	return dt;
}

CDateTime CDateTime::yesterday( const CDateTime& now ){
	return yesterday(now.toTimeStamp());
}

CDateTime CDateTime::lastMonth( const CDateTime& now ){
	return thisMonth(CTimeStamp(now.thisMonth().toTimeStamp().seconds()-24*3600,0));
}

CDateTime CDateTime::lastYear( const CDateTime& now ){
	return thisYear( CTimeStamp(now.thisYear().toTimeStamp().seconds()-24*3600,0) );
}

CDateTime CDateTime::tomorrow( const CDateTime& now ){
	return CDateTime(CTimeStamp(now.today().toTimeStamp().seconds()-24*3600,0));
}

CDateTime CDateTime::nextMonth( const CDateTime& now ){
	CDateTime dt = now.thisMonth();
	if( dt.month()==12 ){
		dt.setYear(dt.year()+1);
		dt.setMonth(1);
	}else{
		dt.setMonth(dt.month()+1);
	}

	return dt;
}

CDateTime CDateTime::nextYear( const CDateTime& now ){
	CDateTime dt = now.thisYear();
	dt.setMonth(12);
	dt.setDay(31);
	return CDateTime(CTimeStamp(dt.toTimeStamp().seconds()+24*3600,0));
}

static const char* weeks[] = {
	"星期日","星期一","星期二","星期三","星期四","星期五","星期六","无效星期"
};

const char* CDateTime::weekStr( const EWeekDay& wday ){
	if( wday<0 || wday>6 )
		return weeks[7];
	return weeks[wday];
}

bool CDateTime::getRtc( CDateTime& dc ){
	dc = CTimeStamp::cur();
	return true;
}

bool CDateTime::setRtc( const CDateTime& dc ){
#ifndef WIN32
	timeval tv;
	CTimeStamp ts;
	dc.toTimeStamp(ts);

	tv.tv_sec = ts.seconds();
	tv.tv_usec = ts.useconds();

	return settimeofday(&tv,NULL)==0;
#else
	return false;
#endif
}

}


